﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xant.FlowEngine.Core;
using Xant.FlowEngine.Interface;
using Xant.FlowEngine.Utility;
using Dapper;

namespace Xant.FlowEngine
{
    /*此类可以考虑采用消息广播的模式，当某个流程对象需要读取或保存时发出请求消息，由某个序列化实现类来响应*/
    /// <summary>
    /// 流程对象序列化管理类
    /// </summary>
    public static class SerializerManager
    {
        private static List<ISerializer> serializers;

        static SerializerManager()
        {
            serializers = new List<ISerializer>();
            //如果配置文件中设置了外部扩展的序列化类，则创建相应的实例，并添加到序列化实例集合中
            var serializerClasses = ConfigurationManager.AppSettings["Serializers"];
            if (!string.IsNullOrEmpty(serializerClasses))
            {
                string[] classes = serializerClasses.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                foreach (var clazz in classes)
                {
                    Type type = Type.GetType(clazz);
                    if (type == null)
                    {
                        throw new ApplicationException("类加载失败，请检查完全限定类名及程序集名称是否正确，且相应的动态库文件是否存在于起始文件夹中。\n" + clazz);
                    }
                    var serializer = Activator.CreateInstance(type) as ISerializer;
                    if (serializer == null)
                    {
                        throw new ApplicationException("该序列化类未实现ISerializer接口：" + clazz);
                    }
                    serializers.Add(serializer);
                }
            }
            //添加默认的序列化类实例
            serializers.Add(new Serialize.DefaultSerializer());
        }

        /*public static int GenerateKey(this IDbTransaction trans, string type)
        {
            char prefix = DBConnectionManager.ProviderType == ProviderType.MySql ? '$' : '@';
            DynamicParameters p = new DynamicParameters();
            p.Add(prefix + "type", type);
            p.Add(prefix + "value", 0, DbType.Int32, ParameterDirection.Output);
            trans.Connection.Execute("GetKey", p, trans, null, CommandType.StoredProcedure);
            int key = p.Get<int>(p.ParameterNames.Last());
            return key;
        }*/

        #region 事件处理
        public static void OnProcessStatusChanged(ProcessInstance process)
        {
            Save(process);
        }

        public static void OnActivityStatusChanged(AbstractActivity activity)
        {
            Save(activity);
        }

        public static void OnWorkitemAfterAction(AbstractWorkitem workitem)
        {
            Save(workitem);
        }

        #endregion

        public static void SaveProcess(ProcessInstance process)
        {
            using (var conn = DBConnectionManager.GetConnection())
            {
                conn.Open();
                var trans = conn.BeginTransaction();
                try
                {
                    SerializerManager.Save(trans, process);
                    SerializerManager.Save(trans, process.Activities.ToArray());
                    SerializerManager.Save(trans, process.Transitions.ToArray());
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    trans.Rollback();
                    throw new ApplicationException("序列化流程实例到数据库时发生异常：\n" + ex.GetExceptionMessages());
                }
            }
        }

        public static ProcessInstance LoadProcess(Guid processId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 读取流程对象
        /// </summary>
        /// <typeparam name="T">流程对象类</typeparam>
        /// <param name="id">主键值</param>
        /// <returns></returns>
        public static T Load<T>(int id) where T : AbstractFlowObject
        {
            var item = default(T);
            bool handled = false;
            foreach (var serializer in serializers)
            {
                item = serializer.Load<T>(null, id, ref handled);
                if (handled)
                    break;
            }
            return item;
        }

        /// <summary>
        /// 保存流程对象
        /// </summary>
        /// <typeparam name="T">流程对象类</typeparam>
        /// <param name="item">流程对象实例</param>
        /// <returns>返回保存到数据库之后最新状态的流程对象</returns>
        public static void Save<T>(params T[] items) where T : AbstractFlowObject
        {
            using (var conn = DBConnectionManager.GetConnection())
            {
                conn.Open();
                var trans = conn.BeginTransaction();
                try
                {
                    Save(trans, items);
                    trans.Commit();
                }
                catch(Exception ex)
                {
                    trans.Rollback();
                }
            }
        }

        /// <summary>
        /// 保存流程对象
        /// </summary>
        /// <typeparam name="T">流程对象类</typeparam>
        /// <param name="item">流程对象实例</param>
        /// <returns>返回保存到数据库之后最新状态的流程对象</returns>
        public static void Save<T>(IDbTransaction trans, params T[] items) where T : AbstractFlowObject
        {
            foreach (var item in items)
            {
                bool handled = false;
                foreach (var serializer in serializers)
                {
                    if (item.RowVersion == 0)//新建的流程对象调用序列化类的Insert方法
                    {
                        serializer.Insert(trans, item, ref handled);
                    }
                    else//修改过的流程对象调用序列化类的Update方法
                    {
                        serializer.Update(trans, item, ref handled);
                    }
                    if (handled)
                        break;
                }
            }
        }

        /// <summary>
        /// 删除流程对象
        /// </summary>
        /// <typeparam name="T">流程对象类</typeparam>
        /// <param name="item">流程对象实例</param>
        public static void Delete<T>(IDbTransaction trans, params T[] items) where T : AbstractFlowObject
        {
            foreach (var item in items)
            {
                bool handled = false;
                foreach (var serializer in serializers)
                {
                    serializer.Delete(trans, item, ref handled);
                    if (handled)
                        break;
                }
            }
        }

        /// <summary>
        /// 删除流程对象(通过主键)
        /// </summary>
        /// <typeparam name="T">流程对象类</typeparam>
        /// <param name="id">主键值</param>
        public static void DeleteById<T>(IDbTransaction trans, int id) where T : AbstractFlowObject
        {
            bool handled = false;
            foreach (var serializer in serializers)
            {
                serializer.DeleteById<T>(trans, id, ref handled);
                if (handled)
                    break;
            }
        }


        internal static void OnWorkitemInitialized(ManualActivity activity)
        {
            var newItems = activity.Workitems.Where(p => p.RowVersion == 0).ToArray();
            Save(newItems);
            //to do: 这里还是再考虑全面一点，会不会重复处理工作项对象的AfterAction事件
            foreach (var workitem in activity.Workitems)
            {
                workitem.AfterAction += OnWorkitemAfterAction;
            }
        }

    }
}
